<template>
	<div :class="[props.isPreview ? 'preview' : 'zj-textEditor']">
		<div :class="[props.isPreview ? '' : 'zj-textEditor-toolBar']">
			<Toolbar v-if="configure.whetherShowToolbar === undefined ? true : configure.whetherShowToolbar
				" :defaultConfig="toolbarConfig" :editor="editorRef" mode="default" />
			<Editor mode="default" v-model="content" :defaultConfig="editorConfig" @onCreated="handleCreated" @onChange="change"
				:class="[props.isPreview ? '' : 'editor']" />
		</div>
	</div>
</template>

<script setup lang="ts">
import { Ref, onBeforeUnmount, shallowRef, ref, watch, nextTick } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { IToolbarConfig, IEditorConfig } from "@wangeditor/editor";
import { PyEditorProps } from "./type";
import "@wangeditor/editor/dist/css/style.css"; // 引入 css

const props = withDefaults(
	defineProps<{
		modelValue: string;
		configure: PyEditorProps;
		isPreview: boolean;
	}>(),
	{
		configure: () => ({
			disabled: false,
			disableImage: true,
			disableVideo: true,
			whetherShowToolbar: true,
			mediaUploadUrl: "",
		}),
		isPreview: false,
	}
);
const emits = defineEmits<{
	"update:modelValue": [string];
	"onChange": [string];
}>();

// 编辑器实例，必须用 shallowRef
const editorRef = shallowRef();
// 内容 HTML
const isDocHtml = /^\n?\t?<!DOCTYPE html>/g;
const isHttpUrl = /^http(s)?.+file\/download\//g;
const content: Ref<string | undefined> = ref(props.modelValue);

const change = () => {
	emt(content.value);
};

watch(
	() => props.configure.disabled,
	async val => {
		val ? editorRef.value?.disable() : editorRef.value?.enable();
	}
);

watch(
	() => props.modelValue,
	async val => {
		if (props.isPreview) {
			nextTick(() => {
				editorRef.value?.dangerouslyInsertHtml(val);
			});
		} else {
			parserVal(val);
		}
	},
	{ immediate: true, deep: true }
);

const emt = (val: any) => {
	emits("onChange", val);
	emits("update:modelValue", val);
};

async function parserVal(val: string) {
	if (!val) val = "<p><br></p>";
	if (isDocHtml.test(val)) {
		if (editorRef.value?.getText()) {
			editorRef.value?.clear();
		}
		editorRef.value?.dangerouslyInsertHtml(val);
	} else if (isHttpUrl.test(val) && props.configure.downloadStream) {
		const arr = val.split("/");
		const res = await props.configure.downloadStream(arr.at(-1)!, val);
		if (res) {
			if (editorRef.value?.getText()) {
				editorRef.value?.clear();
			}
			editorRef.value?.dangerouslyInsertHtml(res);
		}
	} else {
		content.value = val;
	}
}

const toolbarConfig: Partial<IToolbarConfig> = {
	excludeKeys: [
		"insertImage", //不要网络上传图片
		"insertVideo", //不要上传视频
		"uploadVideo", //不要上传本地视频
		"fullScreen", //不要全屏
		"codeBlock", //不要代码块
		"insertVideo",
		"bold",
	],
	// excludeKeys: (() => {
	// 	const imageConfig = props.configure.disableImage ? config.allowImageConfig : [];
	// 	const videoConfig = props.configure.disableVideo ? config.allowVideoConfig : [];
	// 	return [...baseConfig, ...imageConfig, ...videoConfig];
	// })(),
};

const editorConfig: Ref<Partial<IEditorConfig>> = shallowRef({
	readOnly: props.configure.disabled, // 是否禁用
	scroll: false, //是否支持滚动条
	MENU_CONF: {
		// 上传图片
		uploadImage: {
			async customUpload(file: File, insertFn: any) {
				if (props.configure.uploadImage) {
					const res = await props.configure.uploadImage(file);
					if (res) insertFn(`${res.data}`);
				}
			},
		},
	},
});

// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
	// @ts-ignore
	content.value = null;
	const editor = editorRef.value;
	if (editor == null) return;
	editor.destroy();
});

const handleCreated = (editor: any) => {
	editorRef.value = editor; // 记录 editor 实例，重要！
};
</script>

<style lang="scss" scoped>
@include block(textEditor-toolBar) {
	border: 1px solid #ccc;
}

.preview {
	max-width: 35%;
	width: 30%;

	:deep(.w-e-scroll > div) {
		width: 360px !important;
	}
}

:deep(.w-e-scroll > div) {
	// width: 360px !important;
	min-height: 300px !important;
	max-height: 600px !important;
	overflow-y: auto;

	&::-webkit-scrollbar {
		width: 4px;
		/*对垂直流动条有效*/
		height: 0px;
		/*对水平流动条有效*/
	}
}

.editor {
	border-top: 1px solid #ccc;
}

.dist {
	pointer-events: none !important;
}

:deep(.w-e-scroll > div) {
	padding: 10px !important;
}

:deep(.w-e-image-container) {
	margin: 0px !important;
}

:deep(.w-e-image-container > img) {
	width: calc(100% - 2px) !important;
}

:deep(.w-e-scroll) {
	font-size: 16px;
}

:deep(.w-e-scroll > div > p) {
	text-indent: 2em;
	line-height: 2;
}
</style>
